package org.jetbrains.desktop.win32

import org.jetbrains.desktop.win32.generated.NativeKeyState
import org.jetbrains.desktop.win32.generated.NativePhysicalKeyStatus
import org.jetbrains.desktop.win32.generated.desktop_win32_h
import java.lang.foreign.Arena
import java.lang.foreign.MemorySegment

public object Keyboard {
    public fun getKeyState(key: VirtualKey): KeyState = ffiDownCall {
        val nativeKeyState = Arena.ofConfined().use { arena ->
            desktop_win32_h.keyboard_get_key_state(arena, key.value)
        }
        KeyState(
            isDown = NativeKeyState.is_down(nativeKeyState),
            isToggled = NativeKeyState.is_toggled(nativeKeyState),
        )
    }
}

public data class KeyState(
    val isDown: Boolean,
    val isToggled: Boolean,
)

@JvmInline
public value class VirtualKey internal constructor(internal val value: Int) {
    @Suppress("MemberVisibilityCanBePrivate")
    public companion object {
        public val None: VirtualKey = VirtualKey(0)
        public val LeftButton: VirtualKey = VirtualKey(1)
        public val RightButton: VirtualKey = VirtualKey(2)
        public val Cancel: VirtualKey = VirtualKey(3)
        public val MiddleButton: VirtualKey = VirtualKey(4)
        public val XButton1: VirtualKey = VirtualKey(5)
        public val XButton2: VirtualKey = VirtualKey(6)
        public val Back: VirtualKey = VirtualKey(8)
        public val Tab: VirtualKey = VirtualKey(9)
        public val Clear: VirtualKey = VirtualKey(12)
        public val Enter: VirtualKey = VirtualKey(13)
        public val Shift: VirtualKey = VirtualKey(16)
        public val Control: VirtualKey = VirtualKey(17)
        public val Menu: VirtualKey = VirtualKey(18)
        public val Pause: VirtualKey = VirtualKey(19)
        public val CapitalLock: VirtualKey = VirtualKey(20)
        public val Kana: VirtualKey = VirtualKey(21)
        public val Hangul: VirtualKey = VirtualKey(21)
        public val ImeOn: VirtualKey = VirtualKey(22)
        public val Junja: VirtualKey = VirtualKey(23)
        public val Final: VirtualKey = VirtualKey(24)
        public val Hanja: VirtualKey = VirtualKey(25)
        public val Kanji: VirtualKey = VirtualKey(25)
        public val ImeOff: VirtualKey = VirtualKey(26)
        public val Escape: VirtualKey = VirtualKey(27)
        public val Convert: VirtualKey = VirtualKey(28)
        public val NonConvert: VirtualKey = VirtualKey(29)
        public val Accept: VirtualKey = VirtualKey(30)
        public val ModeChange: VirtualKey = VirtualKey(31)
        public val Space: VirtualKey = VirtualKey(32)
        public val PageUp: VirtualKey = VirtualKey(33)
        public val PageDown: VirtualKey = VirtualKey(34)
        public val End: VirtualKey = VirtualKey(35)
        public val Home: VirtualKey = VirtualKey(36)
        public val Left: VirtualKey = VirtualKey(37)
        public val Up: VirtualKey = VirtualKey(38)
        public val Right: VirtualKey = VirtualKey(39)
        public val Down: VirtualKey = VirtualKey(40)
        public val Select: VirtualKey = VirtualKey(41)
        public val Print: VirtualKey = VirtualKey(42)
        public val Execute: VirtualKey = VirtualKey(43)
        public val Snapshot: VirtualKey = VirtualKey(44)
        public val Insert: VirtualKey = VirtualKey(45)
        public val Delete: VirtualKey = VirtualKey(46)
        public val Help: VirtualKey = VirtualKey(47)
        public val Number0: VirtualKey = VirtualKey(48)
        public val Number1: VirtualKey = VirtualKey(49)
        public val Number2: VirtualKey = VirtualKey(50)
        public val Number3: VirtualKey = VirtualKey(51)
        public val Number4: VirtualKey = VirtualKey(52)
        public val Number5: VirtualKey = VirtualKey(53)
        public val Number6: VirtualKey = VirtualKey(54)
        public val Number7: VirtualKey = VirtualKey(55)
        public val Number8: VirtualKey = VirtualKey(56)
        public val Number9: VirtualKey = VirtualKey(57)
        public val A: VirtualKey = VirtualKey(65)
        public val B: VirtualKey = VirtualKey(66)
        public val C: VirtualKey = VirtualKey(67)
        public val D: VirtualKey = VirtualKey(68)
        public val E: VirtualKey = VirtualKey(69)
        public val F: VirtualKey = VirtualKey(70)
        public val G: VirtualKey = VirtualKey(71)
        public val H: VirtualKey = VirtualKey(72)
        public val I: VirtualKey = VirtualKey(73)
        public val J: VirtualKey = VirtualKey(74)
        public val K: VirtualKey = VirtualKey(75)
        public val L: VirtualKey = VirtualKey(76)
        public val M: VirtualKey = VirtualKey(77)
        public val N: VirtualKey = VirtualKey(78)
        public val O: VirtualKey = VirtualKey(79)
        public val P: VirtualKey = VirtualKey(80)
        public val Q: VirtualKey = VirtualKey(81)
        public val R: VirtualKey = VirtualKey(82)
        public val S: VirtualKey = VirtualKey(83)
        public val T: VirtualKey = VirtualKey(84)
        public val U: VirtualKey = VirtualKey(85)
        public val V: VirtualKey = VirtualKey(86)
        public val W: VirtualKey = VirtualKey(87)
        public val X: VirtualKey = VirtualKey(88)
        public val Y: VirtualKey = VirtualKey(89)
        public val Z: VirtualKey = VirtualKey(90)
        public val LeftWindows: VirtualKey = VirtualKey(91)
        public val RightWindows: VirtualKey = VirtualKey(92)
        public val Application: VirtualKey = VirtualKey(93)
        public val Sleep: VirtualKey = VirtualKey(95)
        public val NumberPad0: VirtualKey = VirtualKey(96)
        public val NumberPad1: VirtualKey = VirtualKey(97)
        public val NumberPad2: VirtualKey = VirtualKey(98)
        public val NumberPad3: VirtualKey = VirtualKey(99)
        public val NumberPad4: VirtualKey = VirtualKey(100)
        public val NumberPad5: VirtualKey = VirtualKey(101)
        public val NumberPad6: VirtualKey = VirtualKey(102)
        public val NumberPad7: VirtualKey = VirtualKey(103)
        public val NumberPad8: VirtualKey = VirtualKey(104)
        public val NumberPad9: VirtualKey = VirtualKey(105)
        public val Multiply: VirtualKey = VirtualKey(106)
        public val Add: VirtualKey = VirtualKey(107)
        public val Separator: VirtualKey = VirtualKey(108)
        public val Subtract: VirtualKey = VirtualKey(109)
        public val Decimal: VirtualKey = VirtualKey(110)
        public val Divide: VirtualKey = VirtualKey(111)
        public val F1: VirtualKey = VirtualKey(112)
        public val F2: VirtualKey = VirtualKey(113)
        public val F3: VirtualKey = VirtualKey(114)
        public val F4: VirtualKey = VirtualKey(115)
        public val F5: VirtualKey = VirtualKey(116)
        public val F6: VirtualKey = VirtualKey(117)
        public val F7: VirtualKey = VirtualKey(118)
        public val F8: VirtualKey = VirtualKey(119)
        public val F9: VirtualKey = VirtualKey(120)
        public val F10: VirtualKey = VirtualKey(121)
        public val F11: VirtualKey = VirtualKey(122)
        public val F12: VirtualKey = VirtualKey(123)
        public val F13: VirtualKey = VirtualKey(124)
        public val F14: VirtualKey = VirtualKey(125)
        public val F15: VirtualKey = VirtualKey(126)
        public val F16: VirtualKey = VirtualKey(127)
        public val F17: VirtualKey = VirtualKey(128)
        public val F18: VirtualKey = VirtualKey(129)
        public val F19: VirtualKey = VirtualKey(130)
        public val F20: VirtualKey = VirtualKey(131)
        public val F21: VirtualKey = VirtualKey(132)
        public val F22: VirtualKey = VirtualKey(133)
        public val F23: VirtualKey = VirtualKey(134)
        public val F24: VirtualKey = VirtualKey(135)
        public val NavigationView: VirtualKey = VirtualKey(136)
        public val NavigationMenu: VirtualKey = VirtualKey(137)
        public val NavigationUp: VirtualKey = VirtualKey(138)
        public val NavigationDown: VirtualKey = VirtualKey(139)
        public val NavigationLeft: VirtualKey = VirtualKey(140)
        public val NavigationRight: VirtualKey = VirtualKey(141)
        public val NavigationAccept: VirtualKey = VirtualKey(142)
        public val NavigationCancel: VirtualKey = VirtualKey(143)
        public val NumberKeyLock: VirtualKey = VirtualKey(144)
        public val Scroll: VirtualKey = VirtualKey(145)
        public val LeftShift: VirtualKey = VirtualKey(160)
        public val RightShift: VirtualKey = VirtualKey(161)
        public val LeftControl: VirtualKey = VirtualKey(162)
        public val RightControl: VirtualKey = VirtualKey(163)
        public val LeftMenu: VirtualKey = VirtualKey(164)
        public val RightMenu: VirtualKey = VirtualKey(165)
        public val GoBack: VirtualKey = VirtualKey(166)
        public val GoForward: VirtualKey = VirtualKey(167)
        public val Refresh: VirtualKey = VirtualKey(168)
        public val Stop: VirtualKey = VirtualKey(169)
        public val Search: VirtualKey = VirtualKey(170)
        public val Favorites: VirtualKey = VirtualKey(171)
        public val GoHome: VirtualKey = VirtualKey(172)
        public val VolumeMute: VirtualKey = VirtualKey(173)
        public val VolumeDown: VirtualKey = VirtualKey(174)
        public val VolumeUp: VirtualKey = VirtualKey(175)
        public val MediaNextTrack: VirtualKey = VirtualKey(176)
        public val MediaPreviousTrack: VirtualKey = VirtualKey(177)
        public val MediaStop: VirtualKey = VirtualKey(178)
        public val MediaPlayPause: VirtualKey = VirtualKey(179)
        public val LaunchMail: VirtualKey = VirtualKey(180)
        public val SelectMedia: VirtualKey = VirtualKey(181)
        public val LaunchApplication1: VirtualKey = VirtualKey(182)
        public val LaunchApplication2: VirtualKey = VirtualKey(183)
        public val Oem1: VirtualKey = VirtualKey(186)
        public val OemSemicolon: VirtualKey = VirtualKey(186)
        public val OemPlus: VirtualKey = VirtualKey(187)
        public val OemComma: VirtualKey = VirtualKey(188)
        public val OemMinus: VirtualKey = VirtualKey(189)
        public val OemPeriod: VirtualKey = VirtualKey(190)
        public val Oem2: VirtualKey = VirtualKey(191)
        public val Oem3: VirtualKey = VirtualKey(192)
        public val AbntC1: VirtualKey = VirtualKey(193)
        public val AbntC2: VirtualKey = VirtualKey(194)
        public val GamepadA: VirtualKey = VirtualKey(195)
        public val GamepadB: VirtualKey = VirtualKey(196)
        public val GamepadX: VirtualKey = VirtualKey(197)
        public val GamepadY: VirtualKey = VirtualKey(198)
        public val GamepadRightShoulder: VirtualKey = VirtualKey(199)
        public val GamepadLeftShoulder: VirtualKey = VirtualKey(200)
        public val GamepadLeftTrigger: VirtualKey = VirtualKey(201)
        public val GamepadRightTrigger: VirtualKey = VirtualKey(202)
        public val GamepadDPadUp: VirtualKey = VirtualKey(203)
        public val GamepadDPadDown: VirtualKey = VirtualKey(204)
        public val GamepadDPadLeft: VirtualKey = VirtualKey(205)
        public val GamepadDPadRight: VirtualKey = VirtualKey(206)
        public val GamepadMenu: VirtualKey = VirtualKey(207)
        public val GamepadView: VirtualKey = VirtualKey(208)
        public val GamepadLeftThumbstickButton: VirtualKey = VirtualKey(209)
        public val GamepadRightThumbstickButton: VirtualKey = VirtualKey(210)
        public val GamepadLeftThumbstickUp: VirtualKey = VirtualKey(211)
        public val GamepadLeftThumbstickDown: VirtualKey = VirtualKey(212)
        public val GamepadLeftThumbstickRight: VirtualKey = VirtualKey(213)
        public val GamepadLeftThumbstickLeft: VirtualKey = VirtualKey(214)
        public val GamepadRightThumbstickUp: VirtualKey = VirtualKey(215)
        public val GamepadRightThumbstickDown: VirtualKey = VirtualKey(216)
        public val GamepadRightThumbstickRight: VirtualKey = VirtualKey(217)
        public val GamepadRightThumbstickLeft: VirtualKey = VirtualKey(218)
        public val Oem4: VirtualKey = VirtualKey(219)
        public val Oem5: VirtualKey = VirtualKey(220)
        public val Oem6: VirtualKey = VirtualKey(221)
        public val Oem7: VirtualKey = VirtualKey(222)
        public val Oem8: VirtualKey = VirtualKey(223)
        public val Oem102: VirtualKey = VirtualKey(226)
        public val ImeProcessed: VirtualKey = VirtualKey(229)
        public val Packet: VirtualKey = VirtualKey(231)
        public val DbeAlphanumeric: VirtualKey = VirtualKey(240)
        public val OemAttn: VirtualKey = VirtualKey(240)
        public val DbeKatakana: VirtualKey = VirtualKey(241)
        public val OemFinish: VirtualKey = VirtualKey(241)
        public val DbeHiragana: VirtualKey = VirtualKey(242)
        public val OemCopy: VirtualKey = VirtualKey(242)
        public val DbeSbcsChar: VirtualKey = VirtualKey(243)
        public val OemAuto: VirtualKey = VirtualKey(243)
        public val DbeDbcsChar: VirtualKey = VirtualKey(244)
        public val OemEnlw: VirtualKey = VirtualKey(244)
        public val DbeRoman: VirtualKey = VirtualKey(245)
        public val OemBackTab: VirtualKey = VirtualKey(245)
        public val DbeNoRoman: VirtualKey = VirtualKey(246)
        public val Attn: VirtualKey = VirtualKey(246)
        public val DbeEnterWordRegisterMode: VirtualKey = VirtualKey(247)
        public val CrSel: VirtualKey = VirtualKey(247)
        public val DbeEnterImeConfigMode: VirtualKey = VirtualKey(248)
        public val ExSel: VirtualKey = VirtualKey(248)
        public val DbeFlushString: VirtualKey = VirtualKey(249)
        public val EraseEof: VirtualKey = VirtualKey(249)
        public val DbeCodeInput: VirtualKey = VirtualKey(250)
        public val Play: VirtualKey = VirtualKey(250)
        public val DbeNoCodeInput: VirtualKey = VirtualKey(251)
        public val Zoom: VirtualKey = VirtualKey(251)
        public val DbeDetermineString: VirtualKey = VirtualKey(252)
        public val NoName: VirtualKey = VirtualKey(252)
        public val DbeEnterDlgConversionMode: VirtualKey = VirtualKey(253)
        public val Pa1: VirtualKey = VirtualKey(253)
        public val OemClear: VirtualKey = VirtualKey(254)
    }
}

public data class PhysicalKeyStatus(
    val scanCode: Int,
    val isExtendedKey: Boolean,
    val isMenuKeyDown: Boolean,
    val wasKeyDown: Boolean,
    val isKeyReleased: Boolean,
    val repeatCount: Int,
) {
    internal companion object
}

internal fun VirtualKey.Companion.fromNative(code: Short): VirtualKey {
    val intCode = code.toInt()
    if (intCode == 255) return None // VK__none_
    return VirtualKey(intCode)
}

internal fun PhysicalKeyStatus.Companion.fromNative(native: MemorySegment) = PhysicalKeyStatus(
    scanCode = NativePhysicalKeyStatus.scan_code(native),
    isExtendedKey = NativePhysicalKeyStatus.is_extended_key(native),
    isMenuKeyDown = NativePhysicalKeyStatus.is_menu_key_down(native),
    wasKeyDown = NativePhysicalKeyStatus.was_key_down(native),
    isKeyReleased = NativePhysicalKeyStatus.is_key_released(native),
    repeatCount = NativePhysicalKeyStatus.repeat_count(native),
)
